﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.IO;

namespace Weka
{
    internal class ObjectDeserialiserProviderCreator
    {
        public ObjectDeserialiserProviderCreator(Deserliser deserliser, Dictionary<byte, KeyValueListPair> typeDeserlisers, Key key, byte messageId)
        {
            _deserliser = deserliser;
            _typeDeserlisers = typeDeserlisers;
            Key = key;
            MessageId = messageId;
            MessageType = deserliser.GetMessageType(messageId);
        }
        public Deserliser _deserliser;
        public Dictionary<byte, KeyValueListPair> _typeDeserlisers;
        public Key Key { get; private set; }
        public byte MessageId { get; private set; }
        public Type MessageType { get; private set; }

        public ObjectDeserialiserProvider GetObjectDeserialiserProvider()
        {
            KeyValueListPair a;

            if (!TryGetValue(_typeDeserlisers, MessageId, Key, out a))
            {
                ObjectDeserialiserProvider newObjectDeserialiserProvider = CreateObjectDeserialiserProvider(Key);
                if (_typeDeserlisers.TryGetValue(MessageId, out a))
                    a = a.CloneAndAdd(new KeyValueListPair { RawStructureData = Key.GetRawData(), ObjectDeserialiserProvider = newObjectDeserialiserProvider });
                else
                    a = new KeyValueListPair { RawStructureData = Key.GetRawData(), ObjectDeserialiserProvider = newObjectDeserialiserProvider };

                _typeDeserlisers[MessageId] = a;

                return newObjectDeserialiserProvider;
            }

            return a.ObjectDeserialiserProvider;
        }

        private ObjectDeserialiserProvider CreateObjectDeserialiserProvider(Key key)
        {
            Type mt = _deserliser.GetMessageType(MessageId) ?? typeof(DoNothingMessageReplacement);

            var createGeneric = typeof(ObjectDeserialiserProvider).GetMethod("Create", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(ObjectDeserialiserProviderCreator)}, null);
            var createSpecific = createGeneric.MakeGenericMethod(mt);
            return (ObjectDeserialiserProvider)createSpecific.Invoke(null, new object[] { this});
        }


        internal static bool TryGetValue(Dictionary<byte, KeyValueListPair> typeDeserlisers, byte messageId, Key key, out KeyValueListPair b)
        {
            if (!typeDeserlisers.TryGetValue(messageId, out b)) return false;

            while (b != null && !b.StructureMatches(key)) b = b.Next;//Should generally be the first one.

            return (b != null);
        }


        internal ObjectDeserialiserProviderCreator CreateNewForSubMessage(int messageIndex)
        {
            Key subMessageKey;
            FieldInfo subMessageFieldInfo;
            Key.GetSubKey(messageIndex,out subMessageKey, out subMessageFieldInfo);
            return new ObjectDeserialiserProviderCreator(_deserliser, _typeDeserlisers, subMessageKey, subMessageFieldInfo.MessageId);
        }
    }
}
